package pl.edu.agh.jemo.evolution.operator.crossover.impl;

import pl.edu.agh.jemo.evolution.common.JemoRandom;
import pl.edu.agh.jemo.evolution.operator.crossover.ClassicCrossover;
import pl.edu.agh.jemo.evolution.specimen.Specimen;

/**
 * Specimen generated as a result by this class, are "radial" combination of
 * parent specimen. It means, that in graphical representation of specimen,
 * children will always lie inside a circle, which diameters starts with one and
 * ends with another parent. This crossover uses ClassicCrossover methods for
 * choice of specimen and their processing after recombination is done. Specimen
 * generated by this crossover are unrelated, first childs generated genotype
 * has no impact on second child generation. Note that this crossover is only
 * applicable for 2 dimensional problem. Specimen with longer genotypes, would
 * have the rest of their genotype unaffected.
 * 
 * 
 * @author Marcin Zbijowski
 * 
 */
public class Radial2DCrossover extends ClassicCrossover {

	/**
	 * Generates two children based on parent specimen genotype.
	 * First center of the circle is found. It is average genotype (on the first 2 dimensions) of parents.
	 * Next, method calculates maximal radius, as distance between the middle of the circle and one of parents.
	 * And finally two numbers are generated - distance of new specimen from center (lower than radius), and it's angle.
	 * Using generated values, two new specimen are created and rreturned.
	 * 
	 * @param first First parent used to create new Specimen.
	 * @param second Second parent used to create Specimen.
	 * @return Array of two specimen, which are new instances of specimen of the same type as parents, and with genotype calculated based on parent genotype.
	 */
	@Override
	protected Specimen[] recombinate(Specimen first, Specimen second) {
		Specimen child1 = first.clone();
		Specimen child2 = second.clone();

		double x = (first.getGenotype()[0].asDouble() + second.getGenotype()[0].asDouble())/2.;
		double y = (first.getGenotype()[1].asDouble() + second.getGenotype()[1].asDouble())/2.;

		Specimen[] result = new Specimen[2];
		result[0] = child1;
		result[1] = child2;
	
		double r = first.getEuclideanGenotypeSpaceDistance(second) / 2;
		
		double radius = JemoRandom.getRandom().nextDouble() * r;
		double angle = JemoRandom.getRandom().nextDouble() * 2 * Math.PI;

		child1.getGenotype()[0].fromDouble(x + radius * Math.cos(angle));
		child1.getGenotype()[1].fromDouble(y + radius * Math.sin(angle));

		radius = JemoRandom.getRandom().nextDouble() * r;
		angle = JemoRandom.getRandom().nextDouble() * 2 * Math.PI;

		child2.getGenotype()[0].fromDouble(x + radius * Math.cos(angle));
		child2.getGenotype()[1].fromDouble(y + radius * Math.sin(angle));
		
		return result;
		
	}	
}
